/*!
 * @file areaMenager.cpp
 * @brief Ciało areaMenager.hh
 */

#include "modes/world/area/areaMenager.hh"
using namespace std;

/*--------------------------------------------------------------------------*/

areaMenager::areaMenager() {

	//this->part = new particle(point3f(0, 0, 0), point3f(0.0f, 1.0f, 0.0f),
	//		"pawirr/particles/smoke1.ini");

	this->test = new model("pawirr/models/untitled");

	this->obj = new object(this->test, 8.0f, point3f(60.0f, 100.0f, 100.0f), point3f(0.0f, 0.0f, 0.0f) );//M_PI/2.0f, 0.0f, M_PI));

	this->texturePack = new areaTextures();
}

/*--------------------------------------------------------------------------*/

void areaMenager::loadMap(std::string path) {

	pawirr::graphic->loadingScreen("Wczytawnie pliku konfiguracyjnego...");
	//ETAP 1. Wczytywanie pliku konfigracyjnego.
	this->loadConfig(path);

	pawirr::graphic->loadingScreen("Wczytawnie mapy wysokości...");
	//ETAP 2. Wczytywanie mapy wysokości.
	this->loadHeightmap(path);

	pawirr::graphic->loadingScreen("Wczytawnie sektorów...");
	//ETAP 3. Wczytywanie obszarów (każdy w 3 LoD)
	this->loadSquares();
}

/*--------------------------------------------------------------------------*/

void areaMenager::loadConfig(string dir) {
	/*
	 * TODO Wczytywanie tekstur
	 */
	this->texturePack->texture_r->load("pawirr/textures/ground/sand1.jpg");
	this->texturePack->texture_g->load("pawirr/textures/ground/grass1.jpg");
	this->texturePack->texture_b->load("pawirr/textures/ground/rock1.jpg");

	this->texturePack->texture_detail->load(
			"pawirr/textures/detail/detail1.jpg");

	this->texturePack->texture_map->load(dir + "texmap.png");
	this->texturePack->texture_mapES->load(dir + "esc.png");

	this->texturePack->texture_hmap->load(dir + "hmap.png");

	/*
	 * TODO Informacje wczytane z pliku
	 */
	this->mapTop = 230;
	this->mapBottom = -40;
}

/*--------------------------------------------------------------------------*/

void areaMenager::loadHeightmap(string dir) {

	SDL_Surface *hmap = IMG_Load((dir + "hmap.png").c_str());

	if (hmap == NULL) {
		stringstream ss;
		ss << "Nie znaleziono pliku w '" << dir << "' z mapą wyskości";

		log::error(ss.str());
		return;
	}

	/*
	 * Wymiary w pikselach
	 */
	this->sizeX = hmap->w;
	this->sizeY = hmap->h;

	/*
	 * Wczytywanie pliku z mapą wysokości na surowo [wartości 0-255]
	 */
	this->heightmap = new float[hmap->w * hmap->h];

	for (int y = 0; y < hmap->h; y++) {
		for (int x = 0; x < hmap->w; x++) {

			this->heightmap[x + y * hmap->w] = *((Uint8 *) (hmap->pixels
					+ (int) y * hmap->pitch + x * hmap->format->BytesPerPixel));

			if (this->heightmap[x + y * hmap->w] < 0)
				this->heightmap[x + y * hmap->w] = 0;

			if (this->heightmap[x + y * hmap->w] > 255)
				this->heightmap[x + y * hmap->w] = 0;

		}
	}

	/*
	 * Erozja mapy wysokości
	 */
	for (int y = 2; y < hmap->h - 2; y++) {
		for (int x = 2; x < hmap->w - 2; x++) {

			for (int Y = -2; Y <= 2; Y++) {
				for (int X = -2; X <= 2; X++) {

					if (Y != 0 && Y != 0) {
						this->heightmap[x + y * hmap->w] += this->heightmap[(x
								+ X) + (y + Y) * hmap->w];
					}

				}
			}

			this->heightmap[x + y * hmap->w] = this->heightmap[x + y * hmap->w]
					/ 25;

		}
	}
}

/*--------------------------------------------------------------------------*/
void areaMenager::loadSquares() {

	this->wholeMap = new areaSquare(0, 0, this->sizeX, this->sizeY,
			this->heightmap, this->sizeX, this->sizeY, true);

	this->emptySpace = new areaSquare(0, 0, this->sizeX, this->sizeY, NULL,
			this->sizeX, this->sizeY, false);
}

/*--------------------------------------------------------------------------*/

void areaMenager::draw(area_drawMode dm) {

	int maxDetail = 0;
	bool useShader = true;

	if(dm == area_dm_lowpoly){
		maxDetail = 2;
	}
	else{
		maxDetail = 10;
	}

	if(dm == area_dm_noshader){
		useShader = false;
	}

	this->wholeMap->draw(maxDetail, useShader);

	for (int x = -1; x <= 1; ++x) {
		for (int y = -1; y <= 1; ++y) {

			if (x != 0 || y != 0) {
				this->emptySpace->draw(0, useShader, point2f(x * this->sizeX, y
						* this->sizeY));
			}
		}
	}

	this->obj->draw();
}

/*--------------------------------------------------------------------------*/

point2f areaMenager::getWorldSize() {
	return point2f(this->sizeX, this->sizeY);
}

/*--------------------------------------------------------------------------*/

bool areaMenager::checkPos(point3f pos) {

	if (pos.x < 0 || pos.z < 0 || pos.x > this->sizeX || pos.z > this->sizeY) {
		return false;
	}

	/*
	 * Sprawdzanie wartości terenu
	 */
	int floorX = floor(pos.x);
	int floorY = floor(pos.z);
	int ceilX = ceil(pos.x);
	int ceilY = ceil(pos.z);

	if(floorX == ceilX)
		++ceilX;

	if(floorY == ceilY)
		++ceilY;


	float valA = this->heightmap[floorX + floorY * this->sizeX] - pawirr::graphic->_env->waterLevel;
	float valB = this->heightmap[ceilX + floorY * this->sizeX] - pawirr::graphic->_env->waterLevel;
	float valC = this->heightmap[ceilX + ceilY * this->sizeX] - pawirr::graphic->_env->waterLevel;
	float valD = this->heightmap[floorX + ceilY * this->sizeX] - pawirr::graphic->_env->waterLevel;

	float lengthA = (point3f(floorX, pos.y, floorY) - pos).length();
	float lengthB = (point3f(ceilX, pos.y, floorY) - pos).length();
	float lengthC = (point3f(ceilX, pos.y, ceilY) - pos).length();
	float lengthD = (point3f(floorX, pos.y, ceilY) - pos).length();

	float length = lengthA + lengthB + lengthC + lengthD;

	float average = (valA * (length-lengthA) + valB * (length-lengthB) + valC * (length-lengthC) + valD
			* (length-lengthD)) / ( 3*(lengthA + lengthB + lengthC + lengthD) );

	if (average > pos.y) {
		return false;
	}

	return true;
}

/*--------------------------------------------------------------------------*/
